package com.gitee.wsl.io.api

import kotlinx.io.EOFException
import kotlinx.io.IOException
import kotlinx.io.RawSink
import kotlinx.io.Source

interface ByteSource {

    /**
     * Attempts to fill the buffer with at least [byteCount] bytes of data from the underlying source
     * and returns a value indicating if the requirement was successfully fulfilled.
     *
     * `false` value returned by this method indicates that the underlying source was exhausted before
     * filling the buffer with [byteCount] bytes of data.
     *
     * @param byteCount the number of bytes that the buffer should contain.
     *
     * @throws IllegalArgumentException when [byteCount] is negative.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.request
     */
    public fun request(byteCount: Long): Boolean

    /**
     * Removes a byte from this source and returns it.
     *
     * @throws EOFException when there are no more bytes to read.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readByte
     */
    public fun readByte(): Byte

    /**
     * Removes two bytes from this source and returns a short integer composed of it according to the big-endian order.
     *
     * @throws EOFException when there are not enough data to read a short value.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readShort
     */
    public fun readShort(): Short

    /**
     * Removes four bytes from this source and returns an integer composed of it according to the big-endian order.
     *
     * @throws EOFException when there are not enough data to read an int value.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readInt
     */
    public fun readInt(): Int

    /**
     * Removes eight bytes from this source and returns a long integer composed of it according to the big-endian order.
     *
     * @throws EOFException when there are not enough data to read a long value.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readLong
     */
    public fun readLong(): Long

    /**
     * Reads and discards [byteCount] bytes from this source.
     *
     * @param byteCount the number of bytes to be skipped.
     *
     * @throws EOFException when the source is exhausted before the requested number of bytes can be skipped.
     * @throws IllegalArgumentException when [byteCount] is negative.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.skip
     */
    public fun skip(byteCount: Long)

    /**
     * Removes up to `endIndex - startIndex` bytes from this source, copies them into [sink] subrange starting at
     * [startIndex] and ending at [endIndex], and returns the number of bytes read, or -1 if this source is exhausted.
     *
     * @param sink the array to which data will be written from this source.
     * @param startIndex the startIndex (inclusive) of the [sink] subrange to read data into, 0 by default.
     * @param endIndex the endIndex (exclusive) of the [sink] subrange to read data into, `sink.size` by default.
     *
     * @throws IndexOutOfBoundsException when [startIndex] or [endIndex] is out of range of [sink] array indices.
     * @throws IllegalArgumentException when `startIndex > endIndex`.
     * @throws IllegalStateException when the source is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readAtMostToByteArray
     */
    public fun readAtMostTo(sink: ByteArray, startIndex: Int = 0, endIndex: Int = sink.size): Int

    /**
     * Removes exactly [byteCount] bytes from this source and writes them to [sink].
     *
     * @param sink the sink to which data will be written from this source.
     * @param byteCount the number of bytes that should be written into [sink]
     *
     * @throws IllegalArgumentException when [byteCount] is negative.
     * @throws EOFException when the requested number of bytes cannot be read.
     * @throws IllegalStateException when the source or [sink] is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.readSourceToSink
     */
    public fun readTo(sink: RawSink, byteCount: Long)

    /**
     * Removes all bytes from this source, writes them to [sink], and returns the total number of bytes
     * written to [sink].
     *
     * Return 0 if this source is exhausted.
     *
     * @param sink the sink to which data will be written from this source.
     *
     * @throws IllegalStateException when the source or [sink] is closed.
     * @throws IOException when some I/O error occurs.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.transferTo
     */
     fun transferTo(sink: RawSink): Long

    /**
     * Returns a new [Source] that can read data from this source without consuming it.
     * The returned source becomes invalid once this source is next read or closed.
     *
     * Peek could be used to lookahead and read the same data multiple times.
     *
     * If peek source needs to access more data that this [Source] has in its buffer,
     * more data will be requested from the underlying source and on success,
     * it'll be added to the buffer of this [Source].
     * If the underlying source was exhausted or some error occurred on attempt to fill the buffer,
     * a corresponding exception will be thrown.
     *
     * @throws IllegalStateException when the source is closed.
     *
     * @sample kotlinx.io.samples.KotlinxIoCoreCommonSamples.peekSample
     */
     fun peek(): Source
}